#include "session.h"
#include "../client/responsehandlerthread.h"
#include "../client/responsehandlerthreadpool.h"
#include "userhandler.h"

#include "../service/service.h"
#include "../service/activeservicemanager.h"
#include "utils/logger.h"

#include <QRegExp>
#include <QString>
#include <QStringList>

#include <stdio.h>

    /**
     *   Service name  | Request ID |
     *   "Blog::12324"
     */

void SessionCallback::serviceRequestReceived(const std::string service_name,
                                        const std::string content_type,
                                        unsigned long long content_length,
                                        const void *data)
{
    QString name = QString::fromStdString(service_name);
    QRegExp rx(QString::fromStdString("*::*"));
    rx.setPatternSyntax(QRegExp::Wildcard);

    if (!rx.exactMatch(name))
    {
        // Error, reqeust name is not valid
        return;
    }

    QStringList name_list = name.split(QString::fromStdString("::"));
    std::string service_name_parsed = name_list[0].toStdString();
    std::string request_id = name_list[1].toStdString();

    Service *service = ActiveServiceManager::getInstance()->getServiceByName(service_name_parsed);
    if(service != NULL)
    {
        service->process(m_session->getSessionID(), request_id, content_type, std::string((char*)data));
    }
}

/** Call back from service
 *  Role: UAC
 */
// response received and will notify the application the data received.
void SessionCallback::serviceResponseReceived(const std::string service_name,
                                        const std::string content_type,
                                        unsigned long long content_length,
                                        const void *data)
{
    QString name = QString::fromStdString(service_name);
    QRegExp rx(QString::fromStdString("*::*"));
    rx.setPatternSyntax(QRegExp::Wildcard);

    if (!rx.exactMatch(name))
    {
        // Error, reqeust name is not valid
        return;
    }

    QStringList name_list = name.split(QString::fromStdString("::"));
    std::string service_name_parsed = name_list[0].toStdString();
    std::string request_id = name_list[1].toStdString();

    ResponseHandlerThread *handler_thread = new ResponseHandlerThread();
    ResponseHandlerThreadPool::getInstance()->addHandlerThread(handler_thread);
    handler_thread->setValue(request_id, service_name_parsed, content_type, content_length, data);
    handler_thread->start();

    // Log: new thread to run and it returns
}

void SessionCallback::imReceived(const std::string from,
                    const std::string to,
                    const std::string contact,
                    const std::string mime_type,
                    const std::string body)
{
    LOG_DEBUG("IM message received in session id: %d\n  \
                                    From: %s \n \
                                    To: %s \n \
                                    contact: %s \n \
                                    Mime Type: %s\n \
                                    Message Body: %s\n",
                                    m_session->getSessionID(),
                                    from.c_str(),
                                    to.c_str(),
                                    contact.c_str(),
                                    mime_type.c_str(),
                                    body.c_str());
}

void SessionCallback::imTypingReceived(std::string from,
                    std::string to,
                    std::string contact,
                    bool isTyping)
{
    LOG_DEBUG("IM message received in session id: %d\n  \
                                    From: %s \n \
                                    To: %s \n \
                                    contact: %s \n ",
                                    m_session->getSessionID(),
                                    from.c_str(),
                                    to.c_str(),
                                    contact.c_str());
}

void SessionCallback::serviceInfoReceived(const std::string content_type, unsigned long long content_length,const void *data)
{
    LOG_DEBUG("Service Info received: content type: %s, data: %s", content_type.c_str(), (char*)data);

    m_session->sendServiceInfoSignal((std::string)((char*)data));
}





Session::Session(int session_id, UserHandler *handler)
{
    m_sessionID = session_id;
    m_userHandler = handler;
    m_callback = new SessionCallback(this);
    m_mutex = new QMutex();
    m_info = new PjApiCallInfo();
    initSessionInfo();
}

Session::~Session()
{
    delete m_callback;
    delete m_info;
    delete m_mutex;
}

const std::string Session::getLocalUri()
{
    return m_info->getLocalUri();
}

const std::string Session::getLocalContact()
{
    return m_info->getLocalContact();
}

const std::string Session::getRemoteContact()
{
    return m_info->getRemoteContact();
}

const std::string Session::getRemoteUri()
{
    return m_info->getRemoteUri();
}

void Session::sendServiceResponse(const std::string service_name,
                                const std::string content_type,
                                unsigned long long content_length,
                                const void *data)
{
    QMutexLocker locker(m_mutex);
    std::string name = "Response::" + service_name;


    m_userHandler->sendPackageInSession(m_sessionID, name, content_type, data);
    /** Here we use send request out dialog */
#if 0
    m_userHandler->sendPackageStateless(m_info->getRemoteUri(),
                                        m_info->getLocalUri(),
                                        m_info->getRemoteUri(),
                                        m_info->getLocalContact(),
                                        name,
                                        content_type,
                                        data);
#endif
}

void Session::sendServiceRequest(const std::string service_name,
                    const std::string content_type,
                    unsigned long long content_length,
                    const void *data )
{
    QMutexLocker locker(m_mutex);

    std::string name = "Request::" + service_name;
    m_userHandler->sendPackageInSession(m_sessionID, name, content_type, data);
#if 0
    m_userHandler->sendPackageStateless(m_info->getRemoteUri(),
                                    m_info->getLocalUri(),
                                    m_info->getRemoteUri(),
                                    m_info->getLocalContact(),
                                    name,
                                    content_type,
                                    data);
#endif
}

void Session::initSessionInfo()
{
    m_userHandler->getPjApiHandler()->configCallInfoByID(m_sessionID, &m_info);
}

void Session::sendIM(std::string mime_type, std::string content)
{
    QMutexLocker locker(m_mutex);

    if(m_userHandler->getPjApiHandler()->sendIMInCall(m_sessionID, mime_type, content) == -1)
    {
        //Error: send IM failed
        return;
    }

}

void Session::sendIMTyping(bool is_typing)
{
    QMutexLocker locker(m_mutex);

    if(m_userHandler->getPjApiHandler()->sendIMTypingInCall(m_sessionID, is_typing) == -1)
    {
        //Error: send IM failed
        return;
    }
}

void Session::sendServiceInfo(const std::string content_type,
                        unsigned long long content_length,
                        const void *data)
{
    QMutexLocker locker(m_mutex);

    m_userHandler->sendPackageInSession(m_sessionID, "", content_type, data);
}

void Session::sendServiceInfoSignal(const std::string info_html)
{
    emit serviceInfo(info_html);
}

void Session::run()
{

}
